{#
 # ---------------------------------------------------------------------
 #
 # GLPI - Gestionnaire Libre de Parc Informatique
 #
 # http://glpi-project.org
 #
 # @copyright 2015-2025 Teclib' and contributors.
 # @licence   https://www.gnu.org/licenses/gpl-3.0.html
 #
 # ---------------------------------------------------------------------
 #
 # LICENSE
 #
 # This file is part of GLPI.
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #
 # ---------------------------------------------------------------------
 #}

{% macro largeTitle(label, icon = '', first = false, helper = '') %}
   {% set margins = 'mt-3' %}
   {% if first %}
      {% set margins = 'mt-n2' %}
   {% endif %}

   <div class="card border-0 shadow-none p-0 m-0 {{ margins }}">
      <div class="card-header mb-3 pt-2 border-top rounded-0">
         <h4 class="card-title {{ icon|length ? 'ms-5' : '' }}">
            {% if icon|length %}
               <div class="ribbon ribbon-bookmark ribbon-top ribbon-start bg-blue s-1">
                  <i class="fs-2x {{ icon }}"></i>
               </div>
            {% endif %}
            {{ label }}
            {% if helper is not empty %}
               <span class="form-help" data-bs-toggle="popover" data-bs-placement="top" data-bs-html="true"
                     data-bs-content="{{ helper }}">?</span>
            {% endif %}
         </h4>
      </div>
   </div>
{% endmacro %}

{% macro smallTitle(label, icon = '', helper = '', id = '') %}
   {% set margins = 'mt-2 mb-2' %}
   {% set id = id != '' ? id : 'formsection' ~ random() %}

   <div class="card border-0 shadow-none p-0 m-0 {{ margins }}">
      <div id="{{ id }}" class="card-header mb-1 p-0 ps-3 py-1">
         <h4 class="card-subtitle {{ icon|length ? 'ms-4' : '' }}">
            {% if icon|length %}
               <div class="ribbon ribbon-bookmark ribbon-top ribbon-start bg-blue s-1">
                  <i class="fs-2x {{ icon }}"></i>
               </div>
            {% endif %}
             <span class="ms-2">{{ label }}</span>
            {% if helper is not empty %}
               <span class="form-help" data-bs-toggle="popover" data-bs-placement="top" data-bs-html="true"
                     data-bs-content="{{ helper }}">?</span>
            {% endif %}
         </h4>
      </div>
   </div>
{% endmacro %}

{% macro autoNameField(name, item, label = '', withtemplate = 0, options = {}) %}
   {% set tpl_value = (options.value ?? '')|length > 0 ? options.value : item.fields[name] %}
   {% if item.isTemplate() %} {# TODO exluded types #}
       {% set options = options|merge({
           tpl_mark: item.getAutofillMark(name, {'withtemplate': withtemplate}, tpl_value)
       }) %}
   {% endif %}
   {% if item.fields[name] is defined and item.fields[name] is not null %}
      {% set value = call('autoName', [item.fields[name], name, (withtemplate == 2), item.getType(), item.fields['entities_id'] ?? null]) %}
   {% else %}
      {% set value = null %}
   {% endif %}

   {{ _self.textField(name, value, label, options) }}
{% endmacro %}


{% macro textField(name, value, label = '', options = {}) %}
   {% set options = {
      'id': '%id%'
   }|merge(options) %}

   {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.text(name, value, options) }}
   {% endset %}

   {{ _self.field(name, field, label, options) }}
{% endmacro %}

{% macro urlField(name, value, label = '', options = {}) %}
    {% set options = {
        'id': '%id%'
    }|merge(options) %}

    {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.input(name, value, options|merge({
            'type': 'url'
        })) }}
    {% endset %}

    {{ _self.field(name, field, label, options) }}
{% endmacro %}

{% macro checkboxField(name, value, label = '', options = {}) %}
   {% set options = {
      'id': '%id%',
      'center': true,
   }|merge(options) %}

    {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.checkbox(name, value, options) }}
    {% endset %}

    {{ _self.field(name, field, label, options) }}
{% endmacro %}


{% macro sliderField(name, value, label = '', options = {}) %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {
         'required': true
      }|merge(options) %}
   {% endif %}
   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}
   {% set options = {
      'no_value': 0,
      'yes_value': 1,
      'readonly': false,
      'required': false,
      'disabled': false,
      'additional_attributes': [],
      'label2': '',
   }|merge(options) %}

   {% set field %}
      <label class="form-check form-switch mt-2">
         <input type="hidden"   name="{{ name }}" value="{{ options.no_value }}" />
         <input type="checkbox" name="{{ name }}" value="{{ options.yes_value }}" class="form-check-input" id="%id%"
                {{ value == 1 ? 'checked' : '' }}
                {{ options.readonly ? 'readonly' : '' }}
                {{ options.required ? 'required' : '' }}
                {{ options.disabled ? 'disabled' : '' }}
                {% for attr, value in options.additional_attributes %}
                    {{ attr }}="{{ value }}"
                {% endfor %} />
         {% if options.label2 %}
            <span class="form-check-label">{{ options.label2 }}</span>
         {% endif %}
      </label>
   {% endset %}

   {{ _self.field(name, field, label, options) }}
{% endmacro %}


{% macro numberField(name, value, label = '', options = {}) %}
    {% set options = {
        'id': '%id%'
    }|merge(options) %}

    {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.number(name, value, options) }}
    {% endset %}

    {{ _self.field(name, field, label, options) }}
{% endmacro %}


{% macro readOnlyField(name, value, label = '', options = {}) %}
   {% set options = options|merge({'readonly': true}) %}
   {% set value %}
      <span class="form-control {{ options.input_addclass ?? '' }}" readonly>
         {% if value|length == 0 %}
            &nbsp;
         {% else %}
            {{ value }}
         {% endif %}
      </span>
   {% endset %}
   {{ _self.field(name, value, label, options) }}
{% endmacro %}


{% macro textareaField(name, value, label = '', options = {}) %}
   {% set options = {
      'rand': random(),
      'enable_richtext': false,
      'enable_images': true,
      'enable_fileupload': false,
      'mention_options': {
         'enabled': options.enable_mentions is defined and options.enable_mentions,
         'full': true,
         'users': [],
      },
      'entities_id': session('glpiactive_entity'),
      'uploads': [],
      'rows': 3,
      'readonly': false,
   }|merge(options) %}

   {% if options.id is not defined %}
       {# `id` is mandatory at this point to correctly handle file uploads #}
       {% set options = {id: name ~ '_' ~ options.rand}|merge(options) %}
   {% endif %}

   {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.textarea(name, value, options) }}
   {% endset %}

   {% set add_html = '' %}
   {% if not options.readonly and options.enable_fileupload %}
      {% set add_html %}
         {% do call('Html::file', [{
             'editor_id': options.id,
             'multiple': true,
             'uploads': options.uploads,
             'required': options.fields_template.isMandatoryField('_documents_id')|default(false)
         }]) %}
      {% endset %}
   {% elseif not options.readonly and not options.enable_fileupload and options.enable_richtext and options.enable_images %}
      {% set add_html %}
         {% do call('Html::file', [{
             'editor_id': options.id,
             'name': name,
             'only_uploaded_files': true,
             'uploads': options.uploads,
             'required': options.fields_template.isMandatoryField('_documents_id')|default(false)
         }]) %}
      {% endset %}
   {% endif %}

   {% if add_html != '' %}
      {% if options.add_field_html is defined %}
         {% set add_html = add_html ~ options.add_field_html %}
      {% endif %}
      {% set options = options|merge({'add_field_html': add_html}) %}
   {% endif %}

   {{ _self.field(name, field, label, options) }}
{% endmacro %}


{% macro dateField(name, value, label = '', options = {}) %}
   {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.date(name, value, options) }}
   {% endset %}

   {{ _self.field(name, field, label, options) }}
{% endmacro %}


{% macro datetimeField(name, value, label = '', options = {}) %}
   {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.datetime(name, value, options) }}
   {% endset %}

   {{ _self.field(name, field, label, options) }}
{% endmacro %}


{% macro colorField(name, value, label = '', options = {}) %}
    {% set options = {
        'id': '%id%'
    }|merge(options) %}

    {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.color(name, value, options) }}
    {% endset %}

    {{ _self.field(name, field, label, options) }}
{% endmacro %}


{% macro passwordField(name, value, label = '', options = {}) %}
   {% set options = {
      'id': '%id%',
      'can_regenerate': options.can_regenerate ?? false,
      'clearable': options.clearable is defined ? options.clearable : not (options.is_disclosable ?? false),
      'is_copyable': options.is_disclosable ?? false
   }|merge(options) %}

    {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.password(name, value, options) }}
    {% endset %}

   {# Add checkbox if needed to regenerate password (controler side) #}
   {% if options.can_regenerate %}
      {% set regenerate_chk %}
         <input type="checkbox" name="_regenerate_{{ name }}" id="_regenerate_{{ name }}">&nbsp;<label for="_regenerate_{{ name }}">{{ __('Regenerate') }}</label>
      {% endset %}
      {% set field = field ~ regenerate_chk %}
   {% endif %}

   {{ _self.field(name, field, label, options) }}
{% endmacro %}


{% macro emailField(name, value, label = '', options = {}) %}
    {% set options = {
        'id': '%id%'
    }|merge(options) %}

    {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.email(name, value, options) }}
    {% endset %}

   {{ _self.field(name, field, label, options) }}
{% endmacro %}

{% macro fileField(name, value, label = '', options = {}) %}
   {% set options = {
      'id': '%id%',
      'rand': random(),
      'simple': false,
   }|merge(options) %}
   {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.file(name, value, options) }}
   {% endset %}
   {{ _self.field(name, field, label, options) }}
{% endmacro %}

{% macro imageField(name, value, label = '', options = {}, link_options = {}) %}
   {% set field %}
      <div class="img-overlay-wrapper position-relative">
         {% set clearable = options['clearable'] %}
         {% set url = options['url'] ?? null %}
         {% set options = options|filter((v, k) => k != 'url' and k != 'clearable') %}
         {% if url is not empty %}
            <a href="{{ url }}" {{ call('Html::parseAttributes', [link_options])|raw }}>
         {% endif %}
               <img src="{{ value }}" {{ call('Html::parseAttributes', [options])|raw }} />
         {% if url is not empty %}
            </a>
         {% endif %}
         {% if clearable %}
            <input type="hidden" name="_blank_{{ name }}" />
            <button type="button" class="btn p-2 position-absolute top-0 start-0" title="{{ __('Delete') }}"
                    onclick="const blank_input = $('input[name=\'_blank_{{ name }}\']'); blank_input.val(blank_input.val() ? '' : true); $(this).toggleClass('btn-danger')">
               <i class="ti ti-x"></i>
            </button>
         {% endif %}
      </div>
   {% endset %}
   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}
   {{ _self.field(name, field, label, options) }}
{% endmacro %}

{% macro imageGalleryField(name, value, label = '', options = {}) %}
   {% set field %}
      <div class="picture_gallery d-flex flex-wrap overflow-auto p-3">
         {% for i, picture in value %}
            <div style="position: relative; width: fit-content">
               {{ _self.imageField(name ~ '_' ~ i, picture, '', {
                  'style': 'max-width: 300px; max-height: 150px',
                  'class': 'picture_square',
                  'clearable': options['clearable'],
                  'no_label': true,
               }) }}
            </div>
         {% endfor %}
      </div>
      {{ _self.fileField(name, null, '', {
         'onlyimages': true,
         'multiple': true,
      }) }}
   {% endset %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% set id = (options.id is defined and options.id|length > 0) ? options.id : (name ~ '_' ~ (options.rand ?? "")) %}
   {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
   {{ _inputs.label(label, id, options) }}
   {{ _self.field(name, field, label, options|merge({
      'full_width': true,
      'no_label': true
   })) }}
{% endmacro %}

{% macro hiddenField(name, value, label = '', options = {}) %}
   {% if options.no_label ?? false %}
      {% set options = {
         mb: 'mb-0'
      }|merge(options) %}
   {% endif %}
   {% set field %}
        {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
        {{ _inputs.hidden(name, value, options) }}
   {% endset %}
   {{ _self.field(name, field, label, options) }}
{% endmacro %}

{% macro dropdownNumberField(name, value, label = '', options = {}) %}
    {% set options = {
        'rand': random(),
        'width': '100%',
        'disabled': false,
    }|merge(options) %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %}
   {% endif %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'specific_tags': {'required': true}}|merge(options) %}
   {% endif %}

   {% set field %}
      {% do call('Dropdown::showNumber', [name, {
         'value': value,
         'rand': options.rand
      }|merge(options)]) %}
   {% endset %}

   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownArrayField(name, value, elements, label = '', options = {}) %}
    {% set options = {
        'rand': random(),
        'disabled': false,
        'width': '100%',
    }|merge(options) %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %}
   {% endif %}

   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'required': true}|merge(options) %}
   {% endif %}

   {% set field %}
      {% do call('Dropdown::showFromArray', [name, elements, {
         'value': value,
         'rand': options.rand,
      }|merge(options)]) %}
   {% endset %}

   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownTimestampField(name, value, label = '', options = {}) %}
    {% set options = {
        'rand': random(),
        'width': '100%',
        'disabled': false,
    }|merge(options) %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'required': true}|merge(options) %}
   {% endif %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %}
   {% endif %}

   {% set field %}
      {% do call('Dropdown::showTimestamp', [name, {
         'value': value
      }|merge(options)]) %}
   {% endset %}

   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownYesNo(name, value, label = '', options = {}) %}
    {% set options = {
        'rand': random(),
        'width': '100%',
        'disabled': false
    }|merge(options) %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'required': true}|merge(options) %}
   {% endif %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %}
   {% endif %}

   {% set field %}
      {% do call('Dropdown::showYesNo', [name, value, -1, options]) %}
   {% endset %}

   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownItemTypes(name, value, label = '', options = {}) %}
    {% set options = {
        'rand': random(),
        'width': '100%',
        'disabled': false,
    }|merge(options) %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'required': true}|merge(options) %}
   {% endif %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %}
   {% endif %}

   {% set types = options['types']|default([]) %}

   {% set field %}
      {% do call('Dropdown::showItemTypes', [name, types, {
         'rand': options.rand,
         'value': value
      }|merge(options)]) %}
   {% endset %}

   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownItemsFromItemtypes(name, label = '', options = {}) %}
   {% set options = {
      'rand': random()
   }|merge(options) %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% set field %}
      {% do call('Dropdown::showSelectItemFromItemtypes', [options]) %}
   {% endset %}
   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownIcons(name, value, label = '', options = {}) %}
    {% set options = {
        'rand': random(),
        'width': '100%',
    }|merge(options) %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'required': true}|merge(options) %}
   {% endif %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %}
   {% endif %}

   {% set field %}
      {% do call('Dropdown::dropdownIcons', [name, value, '', options]) %}
   {% endset %}

   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownWebIcons(name, value, label = '', options = {}) %}
    {% set options = {
        rand: random(),
    }|merge(options|merge({
        noselect2: true,
    })) %}
    {# Trim 'ti ' prefix if it exists in the value #}
    {% set value = value|replace({'ti ': ''}) %}

    {{ _self.dropdownArrayField(name, value, {(value): value}, label, options) }}
    <script type="module">
        import('/js/modules/Form/WebIconSelector.js').then((m) => {
            const dropdown_id = '{{ ('dropdown_' ~ name ~ options.rand)|replace({'[': '_', ']': '_'}) }}';
            const selector = new m.default(document.getElementById(dropdown_id));
            selector.init();
        });
    </script>
{% endmacro %}

{% macro dropdownHoursField(name, value, label = '', options = {}) %}
    {% set options = {
        'rand': random(),
        'width': '100%',
        'disabled': false,
    }|merge(options) %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'required': true}|merge(options) %}
   {% endif %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %}
   {% endif %}

   {% set field %}
      {% do call('Dropdown::showHours', [name, {
         'value': value
      }|merge(options)]) %}
   {% endset %}

   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownFrequency(name, value, label = '', options = {}) %}
   {% set options = {
       'rand': random(),
       'disabled': false,
   }|merge(options) %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'required': true}|merge(options) %}
   {% endif %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %}
   {% endif %}

   {% set field %}
      {% do call('Dropdown::showFrequency', [name, value, {
         'width': '100%',
         'value': value
      }|merge(options)]) %}
   {% endset %}

   {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
{% endmacro %}

{% macro dropdownField(itemtype, name, value, label = '', options = {}) %}
   {% if options.multiple ?? false %}
      {# Needed for empty value as the input wont be sent in this case... we need something to know the input was displayed AND empty #}
      {% set defined_input_name = "_#{name}_defined" %}
      <input type="hidden" name="{{ defined_input_name }}" value="1"></input>

      {# Multiple values will be set, input need to be an array #}
      {% set name = "#{name}[]" %}
   {% endif %}
    {% set options = {
        'rand': random(),
        'width': '100%',
        'disabled': false,
    }|merge(options) %}
   {% if options.fields_template.isMandatoryField(name)|default(false) %}
      {% set options = {'specific_tags': {'required': true}}|merge(options) %}
   {% endif %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if options.disabled %}
      {% set options = options|merge({'specific_tags': {'disabled': 'disabled'}}) %}
   {% endif %}

   {% set field %}
      {{ itemtype|itemtype_dropdown({
         'name': name,
         'value': value,
      }|merge(options)) }}
   {% endset %}

   {% if field|trim is not empty %}
      {{ _self.field(name, field, label, options|merge({'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand})) }}
   {% endif %}
{% endmacro %}

{% macro dropdownAjaxField(url, name, value, label = '', options = {}) %}
    {% if options.multiple %}
        {# Needed for empty value as the input wont be sent in this case... we need something to know the input was displayed AND empty #}
        {% set defined_input_name = "_#{name}_defined" %}
        <input type="hidden" name="{{ defined_input_name }}" value="1"></input>

        {# Multiple values will be set, input need to be an array #}
        {% set name = "#{name}[]" %}
    {% endif %}
    {% set options = {
        'rand': random(),
        'width': '100%',
    }|merge(options) %}
    {% if options.fields_template.isMandatoryField(name)|default(false) %}
        {% set options = {'specific_tags': {'required': true}}|merge(options) %}
    {% endif %}

    {% if options.fields_template.isReadonlyField(name)|default(false) %}
        {% set options = options|merge({'readonly': true}) %}
    {% endif %}

    {% if options.disabled %}
        {% set options = options|merge({'specific_tags': {'disabled': 'disabled'}}) %}
    {% endif %}

    {% set options = options|merge({
        'id': 'dropdown_' ~ name|replace({'[': '_', ']': '_'}) ~ options.rand
    }) %}
    {% set field %}
        {% set ajax_opts = options|filter((v, k) => k in ['templateResult', 'templateSelection', 'rand']) %}
        {{ call('Html::jsAjaxDropdown', [name, options.id, url, ajax_opts])|raw }}
    {% endset %}

    {% if field|trim is not empty %}
        {{ _self.field(name, field, label, options) }}
    {% endif %}
{% endmacro %}

{% macro htmlField(name, value, label = '', options = {}) %}
   {% if value|length == 0 %}
      {% set value = '&nbsp;' %}
   {% endif %}
   {% set options = {
      wrapper_class: 'form-control-plaintext'
   }|merge(options) %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% set value %}
      <span class="{{ options.wrapper_class }}">{{ value|raw }}</span>
   {% endset %}
   {{ _self.field(name, value, label, options) }}
{% endmacro %}

{% macro field(name, field, label = '', options = {}) %}
   {% set options = {
      'rand': random(),
      'is_horizontal': true,
      'include_field': true,
      'add_field_html': '',
      'locked': false,
      'locked_fields': [],
       'no_label': false,
   }|merge(options) %}

   {% if options.locked_fields[name] is defined %}
      {% set options = options|merge({'locked': true, 'locked_value': options.locked_fields[name]}) %}
   {% elseif name in options.locked_fields %}
      {% set options = options|merge({'locked': true}) %}
   {% endif %}

   {% if options.fields_template.isReadonlyField(name)|default(false) %}
      {% set options = options|merge({'readonly': true}) %}
   {% endif %}

   {% if not options.include_field %}
      {{ field }}
   {% else %}
      {% set id    = (options.id ?? '')|length > 0 and options.id != '%id%' ? options.id : (name|slug ~ '_' ~ options.rand) %}
      {% set field = field|replace({'%id%': id}) %}
      {% set add_field_html = options.add_field_html|length > 0 ? options.add_field_html : '' %}

      {% if not options.fields_template.isHiddenField(name)|default(false) %}
         {% if options.no_label %}
            {{ _self.noLabelField(field, id, add_field_html, options) }}
         {% elseif options.is_horizontal %}
            {{ _self.horizontalField(label, field, id, add_field_html, options|merge({'name': name})) }}
         {% else %}
            {{ _self.verticalField(label, field, id, add_field_html, options|merge({'name': name})) }}
         {% endif %}
      {% endif %}
   {% endif %}
{% endmacro %}

{% macro ajaxField(id, value, label = '', options = {}) %}
   {% set field %}
      <div id="{{ id }}" class="form-field-ajax">
         {% if value is not null %}
            {{ value|raw }}
         {% endif %}
      </div>
   {% endset %}
   {{ _self.field(id, field, label, options|merge({'id': id ~ '_' ~ options.rand ?? random()})) }}
{% endmacro %}

{% macro nullField(options = {}) %}
   {% set options = {'is_horizontal': true}|merge(options) %}

   {% if options.is_horizontal %}
      {{ _self.horizontalField(null, null, null, null, options) }}
   {% else %}
      {{ _self.verticalField(null, null, null, null, options) }}
   {% endif %}
{% endmacro %}


{% macro noLabelField(field, id = '', add_field_html = '', options = {}) %}
   {% set options = {
      'full_width': false,
      'mb': 'mb-3',
      'add_field_class': '',
      'add_field_attribs': {},
      'inline_add_field_html': false,
   }|merge(options) %}

   {% set class = options.field_class ?? 'col-12 col-sm-6' %}
   {% if options.full_width %}
      {% set class = 'col-12' %}
   {% endif %}
   {% set class = class ~ ' ' ~ options.add_field_class %}

   {% if options.add_field_attribs is not empty %}
      {% set extra_attribs = call('Html::parseAttributes', {options: options.add_field_attribs}) %}
   {% else %}
      {% set extra_attribs = '' %}
   {% endif %}

   <div class="{{ class }} {{ options.mb }} {{ options.inline_add_field_html ? 'd-flex' : '' }}" {{ extra_attribs|raw }}>
      {{ field|raw }}
      {{ add_field_html|raw }}
   </div>
{% endmacro %}


{% macro horizontalField(label, field, id, add_field_html = '', options = {}) %}
   {% set options = {
      'full_width': false,
      'align_label_right': true,
      'mb': 'mb-2',
      'field_class': 'col-12 col-sm-6',
      'container_id': '',
      'add_field_class': '',
      'add_label_class': '',
      'add_field_attribs': {},
      'center': false,
      'label_align': 'end',
      'inline_add_field_html': false,
       'icon_label': false,
   }|merge(options) %}

   {% if options.icon_label %}
      {% set options = {
         label_class: 'col-2',
         input_class: 'col-10',
      }|merge(options) %}
   {% endif %}

   {% if options.full_width %}
      {% set options = options|merge({
         field_class: 'col-12 glpi-full-width',
      }) %}
   {% endif %}

   {% set options = {
      label_class: 'col-xxl-5',
      input_class: 'col-xxl-7',
   }|merge(options) %}

   {% if options.align_label_right %}
      {% set options = options|merge({
         label_class: options.label_class ~ ' text-xxl-' ~ options.label_align,
      }) %}
   {% endif %}

   {% if options.add_field_attribs is not empty %}
      {% set extra_attribs = call('Html::parseAttributes', {options: options.add_field_attribs}) %}
   {% else %}
      {% set extra_attribs = '' %}
   {% endif %}

   {# Usefull for Ajax::updateItemOnSelectEvent (DOM to update) #}
   {% if options.container_id is not empty %}
      {% set container_id = 'id=' ~ options.container_id %}
   {% else %}
      {% set container_id = '' %}
   {% endif %}

   <div class="form-field row align-items-center {{ options.field_class }} {{ options.add_field_class }} {{ options.mb }}" {{ extra_attribs|raw }}>
      {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
      {{ _inputs.label(label, id, options, 'col-form-label ' ~ options.label_class ~ ' ' ~ options.add_label_class) }}
      {% set flex_class = options.center ? 'd-flex align-items-center' : (options.inline_add_field_html ? 'd-flex' : '') %}
      <div {{ container_id }} class="{{ options.input_class }} {{ flex_class }} field-container">
         {{ field|raw }}
         {{ add_field_html|raw }}
      </div>
   </div>
{% endmacro %}


{% macro verticalField(label, field, id, add_field_html = '', options = {}) %}
   {% set options = {
      'full_width': false,
      'mb': 'mb-2',
      'field_class': 'col-12 col-sm-6',
      'add_field_class': '',
      'add_field_attribs': {},
      'insert_content_after_label': '',
      'label_class': '',
      'input_class': '',
   }|merge(options) %}

   {% if options.full_width %}
      {% set options = options|merge({
         field_class: 'col-12',
      }) %}
   {% endif %}

   {% if options.add_field_attribs is not empty %}
      {% set extra_attribs = call('Html::parseAttributes', {options: options.add_field_attribs}) %}
   {% else %}
      {% set extra_attribs = '' %}
   {% endif %}

   <div class="form-field {{ options.field_class }} {{ options.add_field_class }} {{ options.mb }}" {{ extra_attribs|raw }}>
      {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
      <div class="d-flex align-items-center">
         {{ _inputs.label(label, id, options, 'col-form-label ' ~ options.label_class) }}
         {{ options.insert_content_after_label|raw }}
      </div>
      <div class="{{ options.input_class }} field-container">
         {{ field|raw }}
      </div>
      {{ add_field_html|raw }}
   </div>
{% endmacro %}

{% macro label(label, id, options = {}, class = 'form-label') %}
    {% import 'components/form/basic_inputs_macros.html.twig' as _inputs %}
    {{ _inputs.label(label, id, options, class) }}
{% endmacro %}

{% macro codeField(name, value, label, options) %}
    {% set options = {
        single_line: false,
        language: 'twig',
        completions: [],
        helper: __('This field accepts %s content. Press Ctrl+Space to trigger autocompletion.')|format('Twig'),
    }|merge(options) %}

    {% if options.helper is not empty %}
        {% set options = options|merge({
            helper: options.helper|format(options.language)
        }) %}
    {% endif %}

    {% set code_container_id = name ~ '_' ~ random() %}
    {% set code_container %}
        <div id="{{ code_container_id }}" class="form-control overflow-hidden text-start" style="height: {{ options.single_line ? '36px' : options.height|default('auto') }};"></div>
    {% endset %}
    {{ _self.htmlField(name, code_container, label, {
        wrapper_class: 'd-flex flex-grow-1',
    }|merge(options)) }}
    <script>
        $(() => {
            const editor_options = {{ options.single_line ? 'true' : 'false' }} ? window.GLPI.Monaco.getSingleLineEditorOptions() : {};
            window.GLPI.Monaco.createEditor('{{ code_container_id }}', '{{ options.language }}', "{{ value|e('js') }}", {{ options.completions|json_encode|raw }}, editor_options).then(() => {
                $('#{{ code_container_id }}').closest('form').on('formdata', (e) => {
                    const editors = window.monaco.editor.getEditors().filter((editor) => {
                        return editor._domElement.id === '{{ code_container_id }}';
                    });
                    if (editors.length) {
                        e.originalEvent.formData.delete('{{ name }}');
                        e.originalEvent.formData.append('{{ name }}', editors[0].getValue());
                    }
                });
            });
        });
    </script>
{% endmacro %}

{% macro illustrationField(name, value, label = '', options = {}) %}
    {% set options = {
        extra_css_classes: "",
        backdrop: true,
    }|merge(options) %}
    {% set custom_icon_prefix = constant(
        'Glpi\\UI\\IllustrationManager::CUSTOM_ILLUSTRATION_PREFIX'
    ) %}
    {% set field %}
        {% set container_id = "container-" ~ random() %}

        <div id="{{ container_id }}">
            <input
                name="{{ name }}"
                type="hidden"
                value="{{ value }}"
                data-glpi-icon-picker-value
            >

            {# Display the illustration, trigger the modal on click #}
            {% set modal_id = "illustration-modal-" ~ random() %}
            <div
                class="illustration-selector d-flex align-items-center card border-1 {{ options.extra_css_classes }}"
                role="button"
                aria-label="{{ __("Select an illustration") }}"
                data-bs-toggle="modal"
                data-bs-target="#{{ modal_id }}"
                data-glpi-icon-picker-value-preview
            >
                <div class="card-body aspect-ratio-1">
                    {% set is_custom_file = value starts with custom_icon_prefix %}
                    <div
                        {% if is_custom_file %}
                            data-glpi-icon-picker-value-preview-custom
                        {% else %}
                            data-glpi-icon-picker-value-preview-native
                        {% endif %}
                    >
                        {{ render_illustration(value, 100) }}
                    </div>

                    {# Keep the other format (native/custom) that wasn't used
                    in a dedicated div that we can show later if the format
                    is changed #}
                    {% if is_custom_file %}
                        <div
                            class="d-none"
                            data-glpi-icon-picker-value-preview-native
                        >
                           {{ render_illustration('', 100) }}
                        </div>
                    {% else %}
                        <div
                            class="d-none"
                            data-glpi-icon-picker-value-preview-custom
                        >
                           {{ render_illustration(custom_icon_prefix, 100) }}
                        </div>
                    {% endif %}
                </div>
            </div>

            {# Render the modal content #}
            {{ include('components/illustration/icon_picker_modal.html.twig', {
                'id': modal_id,
                'backdrop': options.backdrop,
            }, with_context: false) }}

            {# Start js controller #}
            <script defer type="module">
                (async () => {
                    const module = await import(
                        "/js/modules/IllustrationPicker/Controller.js"
                    );
                    new module.GlpiIllustrationPickerController(
                        document.getElementById('{{ container_id }}'),
                        document.getElementById('{{ modal_id }}'),
                        "{{ custom_icon_prefix }}",
                    );
                })();
            </script>
        </div>
    {% endset %}

    {% set options = {
        'id': '%id%',
    }|merge(options) %}
    {{ _self.field(name, field, label, options) }}
{% endmacro %}
